let _Vue = null
export default class MyRouter {
    // 记录构造函数传入的对象，包括路由规则
    options = {}

    // current 记录当前路由地址
    // 我们需要一个响应式的对象，路由地址发生变化，对应的组件要自动更新
    // 可以通过 Vue.observable 实现
    data = {}

    // 记录路由规则和组件的对应关系，需要把路由规则解析到 routeMap
    routeMap = {}

    // 实现 vue 插件机制
    static install (Vue) {
      // 1.判断当前插件是否已经被安装
      if (MyRouter.install.installed) {
        return
      }
      MyRouter.install.installed = true
      // 2.把Vue记录到全局变量，当前是静态方法，后续要在实例中使用
      _Vue = Vue
      // 3.把 router 实例注册到所有 Vue 实例，$router、$routes
      // _Vue.prototype.$router = this.$options.router
      // 当前 this 指向 MyRouter 类，而不是实例，可以在混入中写
      _Vue.mixin({
        beforeCreate () {
          // 组件没有
          if (!this.$options.router) {
            return
          }
          _Vue.prototype.$router = this.$options.router
          this.$options.router.init()
        }
      })
    }

    // 初始化属性
    constructor (options) {
      this.options = options
      this.routeMap = {}

      // vue提供了三种添加响应式数据的方法 
      //   vue.set   
      //   vue.observable
      //   vue.util.defineReactive
    
      // vue.set：
      //   是在一个已经是响应式对象的基础上添加属性  
      //   官方文档说明：向响应式对象中添加一个 property
      //   并确保这个新 property 同样是响应式的，且触发视图更新
      
      // vue.observable：
      //   是将一个对象改变为响应式对象   
      //   官方文档说明：让一个对象可响应。Vue 内部会用它来处理 data 函数返回的对象
      
      // vue.util.defineReactive：
      //   是内部的一种方法 并没有在文档中对外暴露
      //   功能为向一个对象添加一个属性，属性的值可以是字符串等基本对象

      this.data = _Vue.observable({ current: '/' })
    }

    // 用于初始化
    init () {
      this.createRouteMap()
      this.initComponents(_Vue)
      this.initEvent()
    }

    // 注册popstate，监听浏览器历史的变化
    initEvent () {
      // 没有这个函数，浏览器前进/后退 没有加载组件
      window.addEventListener('popstate', () => {
        this.data.current = window.location.pathname
      })
    }

    // 初始化 routeMap 属性，把路由规则转换成键值对
    createRouteMap () {
      this.options.routes.forEach(route => {
        this.routeMap[route.path] = route.component
      })
    }

    // 创建 router-view、router-link 组件
    initComponents (Vue) {
      Vue.component('router-link', {
        props: {
          to: String
        },
        // 运行时版本没法使用 template 模板
        // template: '<a :href="to"><slot></slot></a>'
        render (h) {
          console.log(this.to)
          return h('a', {
            attrs: {
              href: this.to
            },
            on: {
              click: this.clickHandler
            }
          },
          // 默认插槽
          [this.$slots.default]
          )
        },
        methods: {
          clickHandler (e) {
            // 禁止 a 的默认事件
            history.pushState({}, '', this.to)
            // 修改当前路由，数据变化会自动调用 router-view 的 render
            this.$router.data.current = this.to
            e.preventDefault()
          }
        }
      })
      const _this = this
      Vue.component('router-view', {
        render (h) {
          const component = _this.routeMap[_this.data.current]
          console.log(_this.routeMap, _this.data.current)
          return h(component)
        }
      })
    }
}
